package indi.h.snmp;

import java.io.Closeable;
import java.io.IOException;
import java.util.List;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.TransportMapping;
import org.snmp4j.UserTarget;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OctetString;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.DefaultPDUFactory;
import org.snmp4j.util.TableEvent;
import org.snmp4j.util.TableListener;
import org.snmp4j.util.TableUtils;

/**
 * Snmp获取信息过程 开启snmp 创建target 传输pdu包 获取返回的response
 * 
 * @author hdy
 *
 */
public class SnmpUtil implements Closeable{
	private Snmp snmp = null;
	private TransportMapping transport = null;

	// protected SnmpUtil() {
	//
	// }
	/**
	 * 获取单例对象
	 * 
	 * @return
	 */
	// public static SnmpUtil getSnmpUtil() {
	// return Single.TARGET.getSingle();
	// }
	/**
	 * 枚举实现单例
	 * 
	 * @author Administrator
	 *
	 */
	// private enum Single {
	// TARGET;
	// private SnmpUtil snmpUtil;
	//
	// private Single() {
	// // TODO Auto-generated constructor stub
	// this.snmpUtil = new SnmpUtil();
	// }
	//
	// private SnmpUtil getSingle() {
	// return this.snmpUtil;
	// }
	// }

	/**
	 * 通过snmp的walk模式获取数据
	 * @param addr
	 * @param oids
	 * @param listener
	 * @throws IOException
	 */
	public void syncWalkSnmp(String addr, SnmpParam listener) throws IOException {
		Target target = createTarget(addr, listener);
		SnmpParam s = listener;
		TableUtils utils = new TableUtils(snmp, new DefaultPDUFactory(s.getPduType()));
		if (s.getMaxPduSize() != null)
			utils.setMaxNumRowsPerPDU(s.getMaxPduSize());
		if (s.isSync()) {
			List<TableEvent> l = utils.getTable(target, s.getOids(), s.getLowerItem(), s.getUpperItem());
		} else {
			utils.getTable(target, s.getOids(), new TableListener() {
				
				@Override
				public boolean next(TableEvent event) {
					// TODO Auto-generated method stub
					return false;
				}
				
				@Override
				public boolean isFinished() {
					// TODO Auto-generated method stub
					return false;
				}
				
				@Override
				public void finished(TableEvent event) {
					// TODO Auto-generated method stub
					
				}
			}, null, s.getLowerItem(), s.getUpperItem());
		}
	}
	/**
	 * @return the snmp
	 */
	public Snmp getSnmp() {
		return snmp;
	}

	/**
	 * @param snmp
	 *            the snmp to set
	 */
	public void setSnmp(Snmp snmp) {
		this.snmp = snmp;
	}

	/**
	 * @return the transport
	 */
	public TransportMapping getTransport() {
		return transport;
	}

	/**
	 * @param transport
	 *            the transport to set
	 */
	public void setTransport(TransportMapping transport) {
		this.transport = transport;
	}

	/**
	 * 初始化snmp对象
	 * 
	 * @param ver
	 *            snmp版本
	 * @throws IOException
	 */
	public void init(Integer ver) throws IOException {
		this.transport = new DefaultUdpTransportMapping();
		this.snmp = new Snmp(transport);
		if (ver != null && ver == SnmpConstants.version3) {
			USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
			SecurityModels.getInstance().addSecurityModel(usm);
		}
		this.transport.listen();
	}

	/**
	 * 关闭snmp
	 */
	public void close() {
		try {
			if (this.transport != null)
				this.transport.close();
			if (this.snmp != null)
				this.snmp.close();
		} catch (Exception e) {
			// TODO: handle exception
			if (this.snmp != null) {
				try {
					this.snmp.close();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @param pdu
	 * @param addr
	 * @param listener
	 * @throws IOException
	 */
	public void sendUdpMessage(PDU pdu, String addr, SnmpParam listener) throws IOException {
		Target target = createTarget(addr, listener);
		if (listener.isSync()) {
			this.snmp.send(pdu, target);
		} else {
			this.snmp.send(pdu, target, null, new ResponseListener() {
				
				@Override
				public void onResponse(ResponseEvent event) {
					// TODO Auto-generated method stub
					
				}
			});
		}
	}

	/**
	 * 创建target对象
	 * 
	 * @param addr
	 *            获取snmp目标的地址
	 * @return
	 * @throws IOException
	 */
	private Target createTarget(String addr, SnmpParam snmpParam) throws IOException {
		if (snmp == null)
			init(snmpParam.getVersion());
		Address targetAddress = GenericAddress.parse(addr);
		Target target = null;
		if (snmpParam.getVersion() == SnmpConstants.version3) {
			snmp.getUSM().addUser(snmpParam.getV3Code(), snmpParam.getV3User());
			target = new UserTarget();
			((UserTarget) target).setSecurityLevel(SecurityLevel.AUTH_PRIV);
			((UserTarget) target).setSecurityName(snmpParam.getV3Code());
			target.setVersion(snmpParam.getVersion());
		} else {
			target = new CommunityTarget();
			target.setVersion(snmpParam.getVersion());
			((CommunityTarget) target).setCommunity(snmpParam.getCommunity());
		}
		target.setAddress(targetAddress);
		target.setRetries(snmpParam.getRetries());
		target.setTimeout(snmpParam.getTimeOut());
		return target;
	}

}
